<?php

namespace CZTools\Hyperf\library;

use Tools\Hyperf\Utils;
use think\cache\driver\Redis;
use think\exception\HttpResponseException;
use think\facade\Cache;
use think\facade\Session;
use CZTools\Hyperf\Library\SessionUtil;


class SlideImage
{
    /**
     * 源文件宽度
     */
    private $ORI_WIDTH = 300;
    /**
     * 源文件高度
     */
    private $ORI_HEIGHT = 150;
    /**
     * 模板图宽度
     */
    private $CUT_WIDTH = 50;
    /**
     * 模板图高度
     */
    private $CUT_HEIGHT = 50;
    /**
     * 抠图凸起圆心
     */
    private $circleR = 5;
    /**
     * 抠图内部矩形填充大小
     */
    private $RECTANGLE_PADDING = 8;
    /**
     * 抠图的边框宽度
     */
    private $SLIDER_IMG_OUT_PADDING = 1;


    private $markImage_back;//扣图背景

    private $org_img_folder;//源图文件夹

    private $target_img_folder = "./uploads/huadong";//目标文件夹

    public static $prefix = "splide_image_prefix_";

    private $invalid_times = 600;//时效600秒


    private $org_num = 136;//原图张数

    private static $instance;

    private function __construct()
    {
        $this->markImage_back = "./huadong/background.png";
        $this->org_img_folder = "./huadong/org/";
        $this->target_img_folder = "uploads/huadong";
    }

    public static function getInstance()
    {
        if (!self::$instance instanceof self) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * 根据传入的路径生成指定验证码图片
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    public function getVerifyImage()
    {
        $orgnum = mt_rand(1, $this->org_num);
        $file_path = $this->org_img_folder . "/" . $orgnum . ".jpg";
        $target_folder = $this->target_img_folder;

        if (!is_dir($target_folder)) {
            mkdir($target_folder, 0777, true);
        }
        $imgname = Utils::createGuid();
        $srcImage = imagecreatefromjpeg($file_path);
        $locationX = $this->CUT_WIDTH + mt_rand(0, imagesx($srcImage) - $this->CUT_WIDTH * 3);
        $locationY = $this->CUT_HEIGHT + mt_rand(0, imagesy($srcImage) - $this->CUT_HEIGHT) / 2;
        $markImage = imagecreatefrompng($this->markImage_back);
        imagesavealpha($markImage, true);//这里很重要 意思是不要丢了$sourePic图像的透明色;
        $blockImage = $this->getBlockData();
        $this->cutImgByTemplate($srcImage, $markImage, $blockImage, $locationX, $locationY);

        $org_file = $this->target_img_folder . "/" . $imgname . ".jpg";
        $target_file = $this->target_img_folder . "/" . $imgname . ".png";
        imagejpeg($srcImage, $org_file);
        imagepng($markImage, $target_file);
        imagedestroy($srcImage);
        imagedestroy($markImage);


        $org_base_64 = $this->imgToBase64($org_file);
        $target_base_64 = $this->imgToBase64($target_file);

        unlink($org_file);
        unlink($target_file);

        SessionUtil::save(self::$prefix, [
        "id" => $imgname,
            'locationx' => $locationX,
            'locationy' => $locationY,
            'time' => date("Y-m-d H:i:s"),
            'timestamp' => time()
        ]);

        return ['id' => $imgname, 'org_base_64' => $org_base_64, 'target_base_64' => $target_base_64];
    }

    /**
     * 验证码验证
     * @param $x
     * @param $token
     * @param bool $expire
     * @return array
     */
    public function checkloctionx($x, $token, $expire = false)
    {
        $data = session(self::$prefix);
        if (!$data) {
            return false;
        }

        if ((time() - $data['timestamp']) > $this->invalid_times) {
            return false;

        }

        if ($data['id'] != $token) {
            return false;

        }

        $num = abs($data['locationx'] - $x);
        if ($num < 5) {
            if ($expire) {
                SessionUtil::save(self::$prefix ,NULL);
            }

            return true;
        } else {
            return false;
        }

    }


    /**
     * 生成随机滑块形状
     * <p>
     * 0 透明像素
     * 1 滑块像素
     * 2 阴影像素
     */
    public function getBlockData()
    {

        $CUT_WIDTH = $this->CUT_WIDTH;
        $RECTANGLE_PADDING = $this->RECTANGLE_PADDING;
        $CUT_HEIGHT = $this->CUT_HEIGHT;
        $circleR = $this->circleR;
        $SLIDER_IMG_OUT_PADDING = $this->SLIDER_IMG_OUT_PADDING;
        $data = [];
        //(x-a)²+(y-b)²=r²
        //x中心位置左右5像素随机
        $x1 = $RECTANGLE_PADDING + ($CUT_WIDTH - 2 * $RECTANGLE_PADDING) / 2.0 - 5 + mt_rand(0, 10);
        //y 矩形上边界半径-1像素移动
        $y1_top = $RECTANGLE_PADDING - mt_rand(0, 3);
        $y1_bottom = $CUT_HEIGHT - $RECTANGLE_PADDING + mt_rand(0, 3);
        $y1 = mt_rand(0, 2) == 1 ? $y1_top : $y1_bottom;


        $x2_right = $CUT_WIDTH - $RECTANGLE_PADDING - $circleR + mt_rand(0, 2 * $circleR - 4);
        $x2_left = $RECTANGLE_PADDING + $circleR - 2 - mt_rand(0, 2 * $circleR - 4);
        $x2 = mt_rand(0, 2) == 1 ? $x2_right : $x2_left;
        $y2 = $RECTANGLE_PADDING + ($CUT_HEIGHT - 2 * $RECTANGLE_PADDING) / 2.0 - 4 + mt_rand(0, 10);

        $po = pow($circleR, 2);
        for ($i = 0; $i < $CUT_WIDTH; $i++) {
            for ($j = 0; $j < $CUT_HEIGHT; $j++) {
                //矩形区域
                if (($i >= $RECTANGLE_PADDING && $i < $CUT_WIDTH - $RECTANGLE_PADDING)
                    && ($j >= $RECTANGLE_PADDING && $j < $CUT_HEIGHT - $RECTANGLE_PADDING)) {
                    $data[$i][$j] = 1;
                    $fill = true;
                } else {
                    $data[$i][$j] = 0;
                    $fill = false;
                }
                //凸出区域
                $d3 = pow($i - $x1, 2) + pow($j - $y1, 2);
                if ($d3 < $po) {
                    $data[$i][$j] = 1;
                } elseif (!$fill) {
                        $data[$i][$j] = 0;
                }
                //凹进区域
                $d4 = pow($i - $x2, 2) + pow($j - $y2, 2);
                if ($d4 < $po) {
                    $data[$i][$j] = 0;
                }
            }
        }
        //边界阴影
        for ($i = 0; $i < $CUT_WIDTH; $i++) {
            for ($j = 0; $j < $CUT_HEIGHT; $j++) {
                //四个正方形边角处理
                for ($k = 1; $k <= $SLIDER_IMG_OUT_PADDING; $k++) {
                    //左上、右上
                    if ($i >= $RECTANGLE_PADDING - $k && $i < $RECTANGLE_PADDING
                        && (($j >= $RECTANGLE_PADDING - $k && $j < $RECTANGLE_PADDING)
                            || ($j >= $CUT_HEIGHT - $RECTANGLE_PADDING - $k && $j < $CUT_HEIGHT - $RECTANGLE_PADDING + 1))) {
                        $data[$i][$j] = 2;
                    }

                    //左下、右下
                    if ($i >= $CUT_WIDTH - $RECTANGLE_PADDING + $k - 1 && $i < $CUT_WIDTH - $RECTANGLE_PADDING + 1) {
                        for ($n = 1; $n <= $SLIDER_IMG_OUT_PADDING; $n++) {
                            if ((($j >= $RECTANGLE_PADDING - $n && $j < $RECTANGLE_PADDING)
                                || ($j >= $CUT_HEIGHT - $RECTANGLE_PADDING - $n && $j <= $CUT_HEIGHT - $RECTANGLE_PADDING))) {
                                $data[$i][$j] = 2;
                            }
                        }
                    }
                }

                if ($data[$i][$j] == 1 && $j - $SLIDER_IMG_OUT_PADDING > 0 && $data[$i][$j - $SLIDER_IMG_OUT_PADDING] == 0) {
                    $data[$i][$j - $SLIDER_IMG_OUT_PADDING] = 2;
                }
                if ($data[$i][$j] == 1 && $j + $SLIDER_IMG_OUT_PADDING > 0 && $j + $SLIDER_IMG_OUT_PADDING < $CUT_HEIGHT && $data[$i][$j + $SLIDER_IMG_OUT_PADDING] == 0) {
                    $data[$i][$j + $SLIDER_IMG_OUT_PADDING] = 2;
                }
                if ($data[$i][$j] == 1 && $i - $SLIDER_IMG_OUT_PADDING > 0 && $data[$i - $SLIDER_IMG_OUT_PADDING][$j] == 0) {
                    $data[$i - $SLIDER_IMG_OUT_PADDING][$j] = 2;
                }
                if ($data[$i][$j] == 1 && $i + $SLIDER_IMG_OUT_PADDING > 0 && $i + $SLIDER_IMG_OUT_PADDING < $CUT_WIDTH && $data[$i + $SLIDER_IMG_OUT_PADDING][$j] == 0) {
                    $data[$i + $SLIDER_IMG_OUT_PADDING][$j] = 2;
                }
            }
        }
        return $data;
    }

    /**
     * rgb值转化
     * @param $r
     * @param $g
     * @param $b
     * @return array
     */
    public function RGBtoHSL($r, $g, $b)
    {
        $r /= 255;
        $g /= 255;
        $b /= 255;
        $max = max($r, $g, $b);
        $min = min($r, $g, $b);
        $l = ($max + $min) / 2;
        $d = $max - $min;
        if ($d == 0) {
            $h = $s = 0;
        } else {
            $s = $d / (1 - abs(2 * $l - 1));
            switch ($max) {
                case $r:
                    $h = 60 * fmod((($g - $b) / $d), 6);
                    if ($b > $g) {
                        $h += 360;
                    }
                    break;
                case $g:
                    $h = 60 * (($b - $r) / $d + 2);
                    break;
                case $b:
                    $h = 60 * (($r - $g) / $d + 4);
                    break;
            }
        }
        return array(round($h, 2), round($s, 2), round($l, 2));
    }

    /**
     *
     * @param $h
     * @param $s
     * @param $l
     * @return array
     */
    public function HSLtoRGB($h, $s, $l)
    {
        $c = (1 - abs(2 * $l - 1)) * $s;
        $x = $c * (1 - abs(fmod(($h / 60), 2) - 1));
        $m = $l - ($c / 2);
        if ($h < 60) {
            $r = $c;
            $g = $x;
            $b = 0;
        } else if ($h < 120) {
            $r = $x;
            $g = $c;
            $b = 0;
        } else if ($h < 180) {
            $r = 0;
            $g = $c;
            $b = $x;
        } else if ($h < 240) {
            $r = 0;
            $g = $x;
            $b = $c;
        } else if ($h < 300) {
            $r = $x;
            $g = 0;
            $b = $c;
        } else {
            $r = $c;
            $g = 0;
            $b = $x;
        }
        $r = ($r + $m) * 255;
        $g = ($g + $m) * 255;
        $b = ($b + $m) * 255;
        return array(floor($r), floor($g), floor($b));
    }


    /**
     * 裁剪区块
     * 根据生成的滑块形状，对原图和裁剪块进行变色处理
     * @param oriImage    原图 图片对象
     * @param targetImage 裁剪图 图片对象
     * @param blockImage  滑块 数组
     * @param x           裁剪点x
     * @param y           裁剪点y
     */
    public function cutImgByTemplate($oriImage, $targetImage, $blockImage, $x, $y)
    {

        for ($i = 0; $i < $this->CUT_WIDTH; $i++) {
            for ($j = 0; $j < $this->CUT_HEIGHT; $j++) {
                $_x = $x + $i;
                $_y = $y + $j;
                $rgbFlg = $blockImage[$i][$j];
                if (!$rgbFlg) {
                    continue;
                }
                $rgb = ImageColorAt($oriImage, $_x, $_y);
                $r = ($rgb >> 16) & 0xFF;
                $g = ($rgb >> 8) & 0xFF;
                $b = $rgb & 0xFF;
                $alpha = ($rgb & 0x7F000000) >> 24;

                $tmp = imagecreatetruecolor(1, 1);
                $tmp2 = imagecreatetruecolor(1, 1);
                //深灰色 169,169,169
                //纯白色 	255,255,255

                // 原图中对应位置变色处理
                if ($rgbFlg == 1) {
                    //抠图上复制对应颜色值
                    imagesetpixel($targetImage, $i, $_y, imagecolorallocatealpha($tmp, $r, $g, $b, $alpha));
                    imagesetpixel($oriImage, $_x, $_y, imagecolorallocatealpha($tmp2, 255, 255, 255, 30));
                    //原图对应位置颜色变化
                } else if ($rgbFlg == 2) {
                    imagesetpixel($targetImage, $i, $_y, imagecolorallocatealpha($tmp, 255, 255, 255, $alpha));
                    imagesetpixel($oriImage, $_x, $_y, imagecolorallocatealpha($tmp2, 255, 255, 255, 30));
                } else if ($rgbFlg == 0) {
                    //int alpha = 0;
                    imagesetpixel($targetImage, $i, $j, imagecolorallocatealpha($tmp, 255, 255, 255, 30));
                }
                imagedestroy($tmp);
                imagedestroy($tmp2);
            }

        }
    }


    /**
     * 获取图片的Base64编码(不支持url)
     * @param $img_file 图片路径
     * @return string
     */
    public function imgToBase64($img_file)
    {

        $img_base64 = '';
        if (file_exists($img_file)) {
            $app_img_file = $img_file; // 图片路径
            $img_info = getimagesize($app_img_file); // 取得图片的大小，类型等

            //echo '<pre>' . print_r($img_info, true) . '</pre><br>';
            $fp = fopen($app_img_file, "r"); // 图片是否可读权限

            if ($fp) {
                $filesize = filesize($app_img_file);
                $content = fread($fp, $filesize);
                $file_content = chunk_split(base64_encode($content)); // base64编码
                switch ($img_info[2]) {           //判读图片类型
                    case 1:
                        $img_type = "gif";
                        break;
                    case 2:
                        $img_type = "jpg";
                        break;
                    case 3:
                        $img_type = "png";
                        break;
                }

                $img_base64 = 'data:image/' . $img_type . ';base64,' . $file_content;//合成图片的base64编码

            }
            fclose($fp);
        }

        return $img_base64; //返回图片的base64
    }


}
